/*  ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 
*   Copyright 2014 Jan-Marwin Wollschläger                                   *
*                                                                            *
*   Licensed under the Apache License, Version 2.0 (the "License");          *
*   you may not use this file except in compliance with the License.         *
*   You may obtain a copy of the License at                                  *
*                                                                            *
*       http://www.apache.org/licenses/LICENSE-2.0                           *
*                                                                            *
*   Unless required by applicable law or agreed to in writing, software      *
*   distributed under the License is distributed on an "AS IS" BASIS,        *
*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
*   See the License for the specific language governing permissions and      *
*   limitations under the License.                                           *
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **   */   

import processing.core.*;
import java.util.ArrayList;

class DefaultController implements IController
{
  private IModel model;
  private IView view;
  private PApplet parent;
  private UIMode uiMode;
  private String atomSymbol;
  private Pair previousClick;  // Needed for addition of bonds 
  
  private enum UIMode
  {
	  ADD_ATOMS, ADD_BONDS
  }
  
  public DefaultController(IModel model, IView view, PApplet parent)
  {
    this.model = model; this.view = view;
    this.parent = parent;
    this.uiMode = UIMode.ADD_ATOMS;
    this.atomSymbol = "C";
  }
   
  /**
   * @param model The new model for this IController instance.
   **/
   public void setModel(IModel model)
   {
     this.model = model; 
   }
  
   /**
   * @param view The new view for this IController instance.
   **/
   public void setView(IView view)
   {
     this.view = view; 
   }
   
   /**
   * @param parent The PApplet that should be controlled by this instance, e.g.
   * this controller "listens" for user events on this instance and applies 
   * needed changes to the model.
   **/
   public void control(PApplet parent)
   {
     this.parent = parent; 
   }
   
   /**
    * Handle mouse clicks.
    **/
   public void mouseClicked()
   {
			final float mX = parent.mouseX;//20.0f;
			final float mY = parent.mouseY;
			
			if(parent.mouseButton == parent.RIGHT)
			{
				System.out.println("Right mouse click!");
			}
			
			if(uiMode == UIMode.ADD_ATOMS)
			{
				System.out.println("Adding atom!");
				/* Get the molecules of the current model */
				ArrayList<IMolecule> curMolecules = model.exposeModel();
				
				/* Create a new atom of the kind specified by the user */
				final IAtom      atomToAdd	    = new Atom(atomSymbol);
				
				/* Instantiate an empty molecule */
				final IMolecule moleculeToAdd = new Molecule();
				
				/* Set the position of the atom to mouse coordinates */
				atomToAdd.setPosition(new Vector2(mX, mY));
				
				/* Put the atom into a molecule, yielding a molecule
				* that contains only the single atom atomToAdd.  
				*/
				moleculeToAdd.addAtom(atomToAdd);
				
				/* Add the molecule to the list of molecules */
				curMolecules.add(moleculeToAdd);
				
				/* Update the model to the new molecule list */
				model.updateModel(curMolecules);
			}
			
			if(uiMode == UIMode.ADD_BONDS)
			{
				System.out.println("Adding bond!");
				if(previousClick == null)
				{
					previousClick = new Pair((int)mX, (int)mY);
				}
				else
				{// So previousClick not null
					IAtom fstAtm 	= model.getAtomForClick(previousClick);
					IAtom sndAtm 	= model.getAtomForClick(new Pair((int)mX, (int)mY));
					IMolecule fstMol 	= model.getMoleculeForAtom(fstAtm);
					IMolecule sndMol 	= model.getMoleculeForAtom(sndAtm);
					IMolecule joinedMolecule = fstMol.join(fstAtm, 
														 sndAtm,
														 fstMol,
														 sndMol);
					boolean removedFirst  = model.removeMolecule(fstMol);
					boolean removedSecond = model.removeMolecule(sndMol);
					assert(removedFirst);  // TODO: assertion error thrown
					assert(removedSecond); // when user accidentally 
											// adds bond to atom itself
											// prevent this!
					model.addMolecule(joinedMolecule);  
					
				
					previousClick = null;  // Finally reset previous click	
				}
			}

   }
   
   /**
   * Simple map from an integer to an UIMode enum instance. 
   **/
   private UIMode uiModeFromInteger(int i)
   {
	   if(i <= 0)
	   {
		   return UIMode.ADD_ATOMS;
	   }
	   if(i >= 1)
	   {
		  return UIMode.ADD_BONDS; 
	   }
	   /* To make compiler happy */
	   return UIMode.ADD_BONDS; 
   }
  
  /**
  * Inverse of uiModeFromInteger: This method is a simple map from an
  * UIMode enum instance to an integer. 
  **/
  private int integerFromUIMode(UIMode mode)
  {
	  if(mode == UIMode.ADD_ATOMS)
		return 0;
	  if(mode == UIMode.ADD_BONDS)
		return 1;
	  else
		return -1;
  }
   
   /**
   * Handle pressed keys that were redirected to this instance
   **/
   public void keyPressed()
   {
	   /* User wants to switch mode 'upwards' */
	   if(parent.keyCode == parent.UP)
	   {
		   uiMode = uiModeFromInteger(integerFromUIMode(uiMode)+1);
	   }
	   
	   /* User wants to switch mode 'downwards' */
	   if(parent.keyCode == parent.DOWN)
	   {
		   uiMode = uiModeFromInteger(integerFromUIMode(uiMode)-1);
	   }
   }
}

